package com.exp.base.util;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.Date;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.Assert;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class JsonUtils {
	private static final String DEFAULT_DATE_FORMAT="yyyy-MM-dd HH:mm:ss";  
	private static ObjectMapper objectMapper;
	static {  
        final SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);  
        objectMapper = new ObjectMapper();  
        objectMapper.setDateFormat(dateFormat);
        SimpleModule deserializeModule = new SimpleModule("DeserializeModule", new Version(1, 0, 0, null));
        deserializeModule.addDeserializer(Date.class,new JsonDeserializer<Date>(){
			@Override
			public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
				String value = p.getText();
				try {
					return DateUtils.parseSqlDate(value);
				} catch (ParseException e) {
					throw new IOException(e);
				}
			}
        }).addDeserializer(Time.class,new JsonDeserializer<Time>(){
			@Override
			public Time deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
				String value = p.getText();
				try {
					return DateUtils.parseSqlTime(value);
				} catch (ParseException e) {
					throw new IOException(e);
				}
			}
        });
        objectMapper.registerModule(deserializeModule);
	}
	private static void checkObjectMapper(){
		if(objectMapper==null){
			MappingJackson2HttpMessageConverter converter = SpringUtils.getBean("jacksonConverter");
			objectMapper = converter.getObjectMapper();
		}
	}
	public static<T> T toObject(String jsonStr,Class<T>clazz){
		Assert.notNull(jsonStr, "jsonStr 不能为空");
		Assert.notNull(clazz, "clazz 不能为空");
		checkObjectMapper();
		try {
			return (T)objectMapper.readValue(jsonStr, clazz);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeJsonMappingException(e.getMessage());
		}
	}
	
	public static<T> T toObject(String jsonStr,TypeReference<T>type){
		Assert.notNull(jsonStr, "jsonStr 不能为空");
		Assert.notNull(type, "type 不能为空");
		checkObjectMapper();
		try {
			return (T)objectMapper.readValue(jsonStr, type);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeJsonMappingException(e.getMessage());
		}
	}
	
	public static<T> T toObject(String jsonStr,Type type){
		Assert.notNull(jsonStr, "jsonStr 不能为空");
		Assert.notNull(type, "type 不能为空");
		checkObjectMapper();
		try {
			JavaType javaType = objectMapper.getTypeFactory().constructType(type);
			return (T)objectMapper.readValue(jsonStr, javaType);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeJsonMappingException(e.getMessage());
		}
	}
	
	public static<T> T toObject(Map<?,?> map,Class<T>clazz){
		Assert.notNull(clazz, "clazz 不能为空");
		checkObjectMapper();
		return (T)objectMapper.convertValue(map, clazz);
	}
	
	public static<T> T toObject(Map<?,?> map,TypeReference<T>type){
		Assert.notNull(type, "type 不能为空");
		checkObjectMapper();
		return (T)objectMapper.convertValue(map, type);
	}
	
	public static<T> T toObject(Map<?,?> map,Type type){
		checkObjectMapper();
		JavaType javaType = objectMapper.getTypeFactory().constructType(type);
		return (T)objectMapper.convertValue(map, javaType);
	}
	
	public static<T> String toString(T obj){
		checkObjectMapper();
		try {
			return objectMapper.writeValueAsString(obj);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeJsonMappingException(e.getMessage());
		}
	}
	
	
	
	
}
